home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / CLASSSRC.PAK / REGISTRY.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  21KB  |  811 lines

  1. //----------------------------------------------------------------------------
  2. // Borland WinSys Library
  3. // Copyright (c) 1994, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   5.22  $
  6. //
  7. // General Registry access & registration implementation
  8. //----------------------------------------------------------------------------
  9. #include <winsys/pch.h>
  10. #include <winsys/registry.h>
  11. #include <winsys/system.h>
  12. #include <classlib/pointer.h>
  13. #include <services/checks.h>
  14. #include <stdlib.h>  // atol()
  15. #include <tchar.h>
  16. //#include <stdio.h>   // sprintf()
  17.  
  18. //
  19. // Predefined constant registry keys
  20. //
  21. #if defined(BI_PLAT_WIN16)
  22. # define HKEY_CURRENT_USER           ((HKEY)0x80000001L)
  23. # define HKEY_LOCAL_MACHINE          ((HKEY)0x80000002L)
  24. # define HKEY_USERS                  ((HKEY)0x80000003L)
  25. # define HKEY_PERFORMANCE_DATA       ((HKEY)0x80000004L)
  26. # define HKEY_PERFORMANCE_TEXT       ((HKEY)0x80000050L)
  27. # define HKEY_PERFORMANCE_NLSTEXT    ((HKEY)0x80000060L)
  28. # define HKEY_CURRENT_CONFIG         ((HKEY)0x80000005L)
  29. # define HKEY_DYN_DATA               ((HKEY)0x80000006L)
  30. TRegKey TRegKey::ClassesRoot((TSystem::IsWin95())? ((HKEY)0x80000000L):
  31.                               HKEY_CLASSES_ROOT, true, "HKEY_CLASSES_ROOT");
  32. #else
  33. TRegKey TRegKey::ClassesRoot(HKEY_CLASSES_ROOT, true, "HKEY_CLASSES_ROOT");
  34. #endif
  35. TRegKey TRegKey::ClassesRootClsid(ClassesRoot, "CLSID", KEY_ALL_ACCESS, NoCreate);
  36.  
  37. //
  38. //
  39. //
  40. TRegKey&
  41. TRegKey::GetClassesRoot()
  42. {
  43.   return ClassesRoot;
  44. }
  45.  
  46. //
  47. //
  48. //
  49. TRegKey&
  50. TRegKey::GetClassesRootClsid()
  51. {
  52.   return ClassesRootClsid;
  53. }
  54.  
  55. //
  56. //
  57. //
  58. TRegKey&
  59. TRegKey::GetCurrentUser()
  60. {
  61.   static TRegKey CurrentUser(HKEY_CURRENT_USER, true, "HKEY_CURRENT_USER");
  62.   return CurrentUser;
  63. }
  64.  
  65. //
  66. //
  67. //
  68. TRegKey&
  69. TRegKey::GetLocalMachine()
  70. {
  71.   static TRegKey LocalMachine(HKEY_LOCAL_MACHINE, true, "HKEY_LOCAL_MACHINE");
  72.   return LocalMachine;
  73. }
  74.  
  75. //
  76. //
  77. //
  78. TRegKey&
  79. TRegKey::GetUsers()
  80. {
  81.   static TRegKey Users(HKEY_USERS, true, "HKEY_USERS");
  82.   return Users;
  83. }
  84.  
  85. //
  86. //
  87. //
  88. TRegKey&
  89. TRegKey::GetCurrentConfig()
  90. {
  91.   static TRegKey CurrentConfig(HKEY_CURRENT_CONFIG, true, "HKEY_CURRENT_CONFIG");
  92.   return CurrentConfig;
  93. }
  94.  
  95. //
  96. //
  97. //
  98. TRegKey&
  99. TRegKey::GetDynData()
  100. {
  101.   static TRegKey DynData(HKEY_DYN_DATA, true, "HKEY_DYN_DATA");
  102.   return DynData;
  103. }
  104.  
  105. //
  106. //
  107. //
  108. TRegKey&
  109. TRegKey::GetPerformanceData()
  110. {
  111.   static TRegKey PerformanceData(HKEY_PERFORMANCE_DATA, true, "HKEY_PERFORMANCE_DATA");
  112.   return PerformanceData;
  113. }
  114.  
  115. //
  116. // Different parameter usage & initial code for Win16 vs Win32
  117. //
  118. #if defined(BI_PLAT_WIN16)
  119. //
  120. // Initialize the object with the passed-in data.
  121. //
  122. TRegKey::TRegKey(THandle baseKey, const _TCHAR far* keyName, REGSAM /*samDesired*/, TCreateOK createOK)
  123. :
  124.   Name(strnewdup(keyName)),
  125.   Key(0)
  126. {
  127.   if (createOK == CreateOK) {
  128.     ::RegCreateKey(baseKey, Name, &Key);
  129.   }
  130.   else
  131.     ::RegOpenKey(baseKey, Name, &Key);
  132.  
  133. #else
  134. //
  135. // Initialize the object with the passed-in data.
  136. //
  137. TRegKey::TRegKey(THandle baseKey, const _TCHAR far* keyName, REGSAM samDesired, TCreateOK createOK)
  138. :
  139.   Name(strnewdup(keyName)),
  140.   Key(0)
  141. {
  142.   if (createOK == CreateOK) {
  143.     uint32 disposition;
  144.     ::RegCreateKeyEx(baseKey, Name, 0, ""/*class*/, REG_OPTION_NON_VOLATILE,
  145.                      samDesired, 0/*SecurityAttributes*/, &Key,
  146.                      &disposition);
  147.   }
  148.   else
  149.     ::RegOpenKeyEx(baseKey, Name, 0, samDesired, &Key);
  150. #endif
  151.  
  152.   QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
  153.  
  154.   ShouldClose = true;
  155.  
  156. //  TXRegistry::Check(long(Key), Name);
  157. }
  158.  
  159. //
  160. // Initialize object with the key pointed to by the iterator.
  161. //
  162. #if defined(BI_PLAT_WIN16)
  163. TRegKey::TRegKey(const TRegKeyIterator& iter, REGSAM /*samDesired*/)
  164. #else
  165. TRegKey::TRegKey(const TRegKeyIterator& iter, REGSAM samDesired)
  166. #endif
  167. :
  168.   Key(0),
  169.   Name(new _TCHAR[_MAX_PATH+1])
  170. {
  171.   iter.BaseKey().EnumKey(iter.Current(), Name, _MAX_PATH+1);
  172. #if defined(BI_PLAT_WIN16)
  173.   ::RegOpenKey(iter.BaseKey(), Name, &Key);
  174. #else
  175.   ::RegOpenKeyEx(iter.BaseKey(), Name, 0, samDesired, &Key);
  176. #endif
  177.  
  178.   ShouldClose = true;
  179.   QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
  180. }
  181.  
  182. //
  183. // Construct a TRegKey object around an existing key. Commonly used for
  184. // wrapping the preexisting pseudo-keys.
  185. //
  186. TRegKey::TRegKey(THandle aliasKey, bool shouldClose, const _TCHAR far* keyName)
  187. :
  188.   Key(aliasKey),
  189.   Name(strnewdup(keyName))
  190. {
  191.   ShouldClose = shouldClose;
  192.  
  193. #if defined(BI_PLAT_WIN16)
  194.     long err = QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
  195.     if (err != S_OK)
  196.       Key = 0;
  197. #else
  198. # if defined(BI_COMP_MSC)
  199.   __try {
  200. # else
  201.   try {
  202. # endif
  203.     long err = QueryInfo(0, 0, &SubkeyCount, 0, 0, &ValueCount, 0, 0, 0, 0);
  204.     if (err != S_OK && err != ERROR_INSUFFICIENT_BUFFER)
  205.       Key = 0;
  206.   }
  207.   // Some key handles are unsupported & sometimes the OS crashes, & doesn't
  208.   // just return an error. Catch it here & zero out this key.
  209.   //
  210.   __except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
  211.               EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  212.     Key = 0;
  213.   }
  214. #endif
  215. }
  216.  
  217. //
  218. // Destructor closes the key if necessary and deletes any previously
  219. // allocated memory by the object.
  220. //
  221. TRegKey::~TRegKey()
  222. {
  223.   if (Key && ShouldClose)
  224.     ::RegCloseKey(Key);
  225.   delete[] Name;
  226. }
  227.  
  228. #if defined(BI_PLAT_WIN16)
  229. //
  230. // Query information about the key.
  231. // Emulation for 16-bits.
  232. //
  233. long
  234. TRegKey::QueryInfo(_TCHAR far* /*class_*/, uint32* /*classSize*/,
  235.                         uint32* subkeyCount,
  236.                         uint32* /*maxSubkeySize*/, uint32* /*maxClassSize*/,
  237.                         uint32* valueCount, uint32* /*maxValueName*/,
  238.                         uint32* /*maxValueData*/, uint32* /*secDescSize*/,
  239.                         FILETIME far* /*lastWriteTime*/)
  240. {
  241.   // Ug. Enum all subkeys to count them ahead of time for iterator
  242.   //
  243.   if (subkeyCount) {
  244.     int i = 0;
  245.     for (;; i++) {
  246.       _TCHAR dummy[_MAX_PATH+1];
  247.       long r = ::RegEnumKey(Key, i, dummy, sizeof dummy);
  248.       if (r != 0/* && r != ERROR_MORE_DATA*/)
  249.         break;
  250.     }
  251.     *subkeyCount = i;
  252.   }
  253.   if (valueCount)
  254.     *valueCount = 1;    // Cannot access named values with Win16 API
  255.   return 0;
  256. }
  257. #else
  258. //
  259. // Wrapper for RegQueryInfoKey API.
  260. //
  261. long
  262. TRegKey::QueryInfo(_TCHAR far* class_, uint32* classSize,
  263.                    uint32* subkeyCount,  uint32* maxSubkeySize,
  264.                    uint32* maxClassSize, uint32* valueCount,
  265.                    uint32* maxValueName, uint32* maxValueData,
  266.                    uint32* secDescSize, PFILETIME lastWriteTime)
  267. {
  268.   _TCHAR      db[256];
  269.   uint32    d1 = sizeof db;
  270.   uint32    d2 = 0;
  271.   uint32    d3 = 0;
  272.   uint32    d4 = 0;
  273.   uint32    d5 = 0;
  274.   uint32    d6 = 0;
  275.   uint32    d7 = 0;
  276.   uint32    d8 = 0;
  277.   FILETIME  ft;
  278.  
  279.   // NT 3.50 has trouble with 0 ptrs for some of these
  280.   //
  281.   return ::RegQueryInfoKey(Key, class_ ? class_ : db,
  282.                            classSize ? classSize : &d1, 0,
  283.                            subkeyCount ? subkeyCount : &d2,
  284.                            maxSubkeySize ? maxSubkeySize : &d3,
  285.                            maxClassSize ? maxClassSize : &d4,
  286.                            valueCount ? valueCount : &d5,
  287.                            maxValueName ? maxValueName : &d6,
  288.                            maxValueData ? maxValueData : &d7,
  289.                            secDescSize ? secDescSize : &d8,
  290.                            lastWriteTime ? lastWriteTime : &ft);
  291. }
  292. #endif
  293.  
  294. //
  295. // Completely nuke a child key, including any of its subkeys. RegDeleteKey
  296. // fails if a key has subkeys, so must tail-recurse to clean them up first.
  297. //
  298. long
  299. TRegKey::NukeKey(const _TCHAR far* subKeyName)
  300. {
  301.   {
  302.     TRegKey subKey(*this, subKeyName, KEY_ALL_ACCESS, TRegKey::NoCreate);
  303.  
  304.     // Don't increment since deleting & all subkeys will slide down to 0
  305.     //
  306.     for (TRegKeyIterator i(subKey); i; ) {
  307.       TRegKey subSubKey(i);
  308.       if (!subSubKey)
  309.         break;     // All done, ran out before iterator knew, since deleting
  310.       long err = subKey.NukeKey(subSubKey.GetName());
  311.       if (err)
  312.         return err;
  313.     }
  314.   }
  315.   return DeleteKey(subKeyName);
  316. }
  317.  
  318. //
  319. // Create a value object named 'name' associated with the the current key.
  320. //
  321. TRegValue::TRegValue(const TRegKey& key, const _TCHAR far* name)
  322. :
  323.   Key(key), Name(name), AName(0), Data(0)
  324. {
  325.   DataSize = 0;
  326.   Key.QueryValue(Name, &DataType, 0, &DataSize); // Get type & size only
  327. }
  328.  
  329. //
  330. // Create a value object pointed to by the current position of the iterator.
  331. //
  332. TRegValue::TRegValue(const TRegValueIterator& iter)
  333. :
  334.   Key(iter.BaseKey()), Data(0)
  335. {
  336.   uint32 nameSize = _MAX_PATH; //0;  
  337.   Name = AName = new _TCHAR[(int)nameSize];
  338.   DataSize = 0;
  339.   Key.EnumValue(iter.Current(), AName, nameSize, &DataType, 0, &DataSize);
  340. }
  341.  
  342. //
  343. // Destructor deletes any previously allocated memory.
  344. //
  345. TRegValue::~TRegValue()
  346. {
  347.   delete[] AName;
  348.   delete[] Data;
  349. }
  350.  
  351. //
  352. // Retrieve the data for the value.
  353. //
  354. void
  355. TRegValue::RetrieveOnDemand() const
  356. {
  357.   if (!Data) {
  358. #if defined(BI_NO_MUTABLE)
  359.     CONST_CAST(TRegValue*,this)->Data = new uint8[DataSize];
  360. #else
  361.     Data = new uint8[(int)DataSize];
  362. #endif
  363.     uint32 ds = DataSize;
  364.     Key.QueryValue(Name, 0, Data, &ds);  // DataSize shouldn't change...
  365.   }
  366. }
  367.  
  368. //
  369. // Set the data for the value.
  370. //
  371. long
  372. TRegValue::Set(uint32 type, uint8* data, uint32 dataSize)
  373. {
  374.   long ret = Key.SetValue(Name, type, data, dataSize);
  375.   if (ret == 0) {
  376.     DataType = type;
  377.     if (dataSize == DataSize) {
  378.       memcpy(Data, data, (int)DataSize);  // resync w/ new data if same size
  379.     }
  380.     else {
  381.       DataSize = dataSize;           // Otherwise retrieve on demand later
  382.       delete[] Data;
  383.       Data = 0;
  384.     }
  385.   }
  386.   return ret;
  387. }
  388.  
  389. //----------------------------------------------------------------------------
  390.  
  391. //
  392. // Registry exception checking. Throw a TXRegistry if arg is non-zero
  393. //
  394. void
  395. TXRegistry::Check(long stat, const _TCHAR* key)
  396. {
  397.   if (stat != 0 && !InstanceCount) {
  398.     if (stat == 1)      // default bool true to a generic E_FAIL
  399.       stat = E_FAIL;
  400.     _TCHAR buf[100];
  401.     if (key)
  402.       wsprintf(buf, "Registry failure on key: %s, ErrorCode = %lX\n",
  403.                (const _TCHAR far*)key, stat);
  404.     else
  405.       wsprintf(buf, "Registry failure on unknown key: ErrorCode = %lX\n",
  406.                stat);
  407.     WARN(stat != 0, buf);
  408.     throw TXRegistry(buf, key);
  409.   }
  410. }
  411.  
  412. //----------------------------------------------------------------------------
  413.  
  414. //
  415. // Initialize object with the passed-in data.
  416. // Counts the number of items in the list.
  417. //
  418. TRegTemplateList::TRegTemplateList(TRegKey& basekey, const _TCHAR* list[])
  419. :
  420.   BaseKey(basekey),
  421.   List(list)
  422. {
  423.   PRECONDITION(List);
  424.  
  425.   for (Count = 0; List[Count]; Count++)
  426.     ;
  427.   EnabledFlags = new _TCHAR[Count];
  428. }
  429.  
  430. //
  431. // Destructor deletes any previously allocated memory.
  432. //
  433. TRegTemplateList::~TRegTemplateList()
  434. {
  435.   delete[] EnabledFlags;
  436. }
  437.  
  438. //
  439. // Enable items from the set.
  440. //
  441. void
  442. TRegTemplateList::Enable(const _TCHAR* set)
  443. {
  444.   for (const _TCHAR* pc = set; *pc != 0; pc++)
  445.     EnabledFlags[*pc - 1] = 0;                 // Selectively allow enable
  446. }
  447.  
  448. //
  449. // Activate the items in the set.
  450. //
  451. void
  452. TRegTemplateList::Activate(const _TCHAR* set)
  453. {
  454.   for (const _TCHAR* pc = set; *pc != 0; pc++)
  455.     EnabledFlags[*pc - 1]++;  
  456. }
  457.  
  458. //----------------------------------------------------------------------------
  459.  
  460. //
  461. // Initialize the object with the passed-in data.
  462. // Counts the number of items in the list.
  463. //
  464. TRegParamList::TRegParamList(TEntry* list)
  465. :
  466.   List(list)
  467. {
  468.   PRECONDITION(List);
  469.  
  470.   for (Count = 0; List[Count].Param; Count++)
  471.     ;
  472.   typedef const _TCHAR* cpchar;
  473.   Values = new cpchar[Count];
  474. }
  475.  
  476. //
  477. // Destructor deletes any previously allocated memory.
  478. //
  479. TRegParamList::~TRegParamList()
  480. {
  481.   delete[] Values;
  482. }
  483.  
  484. //
  485. // Reset all values to their default values.
  486. //
  487. void
  488. TRegParamList::ResetDefaultValues()
  489. {
  490.   for (int i = Count; --i >= 0; )
  491.     Values[i] = List[i].Default;
  492. }
  493.  
  494. //
  495. // Look for a given param in this param list
  496. //
  497. int TRegParamList::Find(const _TCHAR* param)
  498. {
  499.   PRECONDITION(param);
  500.   if (!param)
  501.     return -1;
  502.  
  503.   int i = Count;
  504.   while (--i >= 0) {
  505.     if (_tcscmp(List[i].Param, param) == 0)
  506.       break;
  507.   }
  508.   return i;
  509. }
  510.  
  511. //----------------------------------------------------------------------------
  512.  
  513. //
  514. // Initialize the symbol table with the data.
  515. //
  516. TRegSymbolTable::TRegSymbolTable(TRegKey& basekey, const _TCHAR* tplList[],
  517.                                  TRegParamList::TEntry* paramList)
  518. :
  519.   Templates(basekey, tplList),
  520.   Params(paramList)
  521. {
  522.   UserKeyCount = 0;
  523. }
  524.  
  525. //
  526. // Enable all templates, or if filter is given enable only those
  527. // Initialize paramater values with defaults
  528. //
  529. void
  530. TRegSymbolTable::Init(_TCHAR* filter)
  531. {
  532.   if (filter) {
  533.     Templates.DisableAll();
  534.     Templates.Enable(filter);
  535.   }
  536.   else {
  537.     Templates.EnableAll();
  538.   }
  539.  
  540.   Params.ResetDefaultValues();
  541.   UserKeyCount = 0;
  542. }
  543.  
  544. //
  545. // Scan through provided items assinging values from the item to the matching
  546. // param. A langId is needed for locale translation on assignment.
  547. //
  548. void
  549. TRegSymbolTable::UpdateParams(TLangId lang, TRegItem* item)
  550. {
  551.   for (; item && item->Key; item++) {
  552.     // Note presence of user-specified key and value, process when streaming
  553.     //
  554.     if (*item->Key == ' ') {
  555.       UserKeyCount++;
  556.     }
  557.     else {
  558.       // Replace default with user-specified parameter value
  559.       //
  560.       int i = Params.Find(item->Key);
  561.       TXRegistry::Check(i < 0, item->Key);
  562.       Params.Value(i) = item->Value.Translate(lang);
  563.  
  564.       // Activate all templates invoked by parameter
  565.       //
  566.       Templates.Activate(Params[i].TemplatesNeeded);
  567.     }
  568.   }
  569. }
  570.  
  571. //
  572. // Scan thru and process enabled templates, substituting filled in parameter
  573. // values and streaming the resulting strings into the out stream provided.
  574. //
  575. void
  576. TRegSymbolTable::StreamOut(TRegItem* item, ostream& out)
  577. {
  578.   for (int itpl = 1; itpl <= Templates.GetCount() || UserKeyCount--; itpl++) {
  579.  
  580.     // Setup pt from standard templates, or from userKeys in item prepended
  581.     // by spaces.
  582.     //
  583.     const _TCHAR* userval = 0;
  584.     const _TCHAR* pt;
  585.     if (itpl <= Templates.GetCount()) {  // Processing standard template array
  586.       if (!Templates.IsActive(itpl))
  587.         continue;
  588.       pt = Templates[itpl];
  589.     }
  590.     else {                            // Now processing user-defined templates
  591.       while (*(pt = item->Key) != ' ')
  592.         item++;
  593.       pt++;
  594.       userval = item->Value;
  595.     }
  596.  
  597.     // Walk thru template (pt) copying it into buf, replacing <params> on the
  598.     // way.
  599.     //
  600.     const int bufSize  = 512;
  601.     TAPointer<_TCHAR> buf = new _TCHAR[bufSize];
  602.  
  603.     _TCHAR*       data = 0; // Optional data for keys-value=data
  604.     const _TCHAR* pc;       // Point where param token began
  605.     _TCHAR*       pb = buf; // Working buffer write pointer
  606.     for (;;) {
  607.       _TCHAR  c = *pt++;  // Current character being copied
  608.       switch (c) {
  609.         case '<':
  610.           pc = pb;      // Remember where param token starts
  611.           continue;
  612.         case '>': {
  613.           *pb = 0;        // Terminate param token
  614.  
  615.           // Lookup param in param list
  616.           //
  617.           int i = Params.Find(pc);
  618.           TXRegistry::Check(i < 0, pc); // internal err
  619.  
  620.           // Now get the value obtained above
  621.           //
  622.           pb = (_TCHAR*)pc; // Move buffer ptr back
  623.           TXRegistry::Check((pc = Params.Value(i)) == 0, Params[i].Param);
  624.  
  625.           if (*pc == 0 && *pt == ' ')  
  626.             pt++;
  627.  
  628.           // Copy value to buf
  629.           //
  630.           while (*pc != 0)
  631.             *pb++ = *pc++;
  632.           continue;
  633.         }
  634.         case '=':
  635.           while (*(pb-1) == ' ')  // Remove trailing space before =
  636.             pb--;
  637.           *pb++ = 0;              // Terminate keys-value
  638.           data = pb;              // Rest of pt will be data written from here
  639.           while (*pt == ' ')
  640.             pt++;
  641.           continue;
  642.         default:
  643.           *pb++ = c;  // Copy character to buf. Param name will be overwriten
  644.           continue;
  645.         case 0:
  646.           *pb++ = 0;
  647.           if (!userval)
  648.             break;
  649.           pt = userval;
  650.           userval = 0;
  651.           data = pb;
  652.           continue;
  653.       }
  654.       if (!c)
  655.         break;
  656.     }
  657.     // Now write out a key with an optional assignment value to output stream
  658.     //
  659.     out
  660. #if defined(BI_DATA_NEAR)
  661.       << TResId(Templates.GetBaseKey().GetName())
  662. #else
  663.       << Templates.GetBaseKey().GetName()
  664. #endif
  665.       << '\\' << (const _TCHAR*)buf;
  666.     if (data)
  667.       out << " = " << data;
  668.     out << '\n';
  669.   }
  670. }
  671.  
  672. //----------------------------------------------------------------------------
  673.  
  674. //
  675. // Walk thru an input stream and use "basekey\key\key=data" lines to set
  676. // registry entries
  677. // Has named value support in the form "basekey\key\key|valuename=data"
  678. //
  679. void TRegistry::Update(TRegKey& baseKey, istream& in)
  680. {
  681.   // Loop thru all lines in input stream
  682.   //
  683.   while (!in.eof()) {
  684.     // Get line into entry buffer, skip over base key if it exists, ignore line
  685.     // if it doesn't
  686.     //
  687.     _TCHAR entry[512];
  688.     in.getline(entry, _tcslen(baseKey.GetName())+1);
  689.     if (_tcscmp(entry, baseKey.GetName()) != 0)
  690.       continue;
  691.     in.getline(entry, 1+1);  // Eat the '\' separator
  692.     in.getline(entry, sizeof entry);
  693.  
  694.     // Split entry into keys-value and data strings
  695.     //
  696.     _TCHAR* data = _tcschr(entry, '=');
  697.     if (data) {
  698.       _TCHAR* pc = data;
  699.       while (*(pc-1) == ' ')
  700.         pc--;
  701.       *pc = 0;
  702.       while (*(++data) == ' ')
  703.         ;
  704.     }
  705.     else
  706.       data = "";
  707.     _TCHAR* valName = _tcschr(entry, '|');
  708.     if (valName)
  709.       *valName++ = 0;  // Terminate key at value name separator
  710.  
  711.     // Set default value
  712.     //
  713.     if (valName) {
  714.       TRegKey subKey(baseKey, entry);
  715.       TXRegistry::Check(subKey.SetValue(valName, REG_SZ, (const uint8*)data, 0), entry);
  716.     }
  717.     else {
  718.       TXRegistry::Check(baseKey.SetDefValue(entry, REG_SZ, data, 0), entry);
  719.     }
  720.   }
  721. }
  722.  
  723. //
  724. // Walk thru an input stream and use "basekey\key\key=data" lines to check
  725. // registry entries.
  726. // Return the number of differences. Zero means a complete match
  727. //
  728. // Has named value support in the form "basekey\key\key|valuename=data"
  729. //
  730. int TRegistry::Validate(TRegKey& baseKey, istream& in)
  731. {
  732.   int diffCount = 0;
  733.   while (!in.eof()) {
  734.     // Get line into entry buffer, skip over hive key if it exists, ignore line
  735.     // if it doesn't
  736.     //
  737.     _TCHAR entry[512];
  738.     in.getline(entry, _tcslen(baseKey.GetName())+1);  // 1 for '\', 1 for 0
  739.     if (_tcscmp(entry, baseKey.GetName()) != 0)
  740.       continue;
  741.     in.getline(entry, 1+1);  // Eat the '\' separator
  742.     in.getline(entry, sizeof entry);
  743.  
  744.     // Split entry into keys-value and data strings
  745.     //
  746.     _TCHAR* data = _tcschr(entry, '=');
  747.     if (data) {
  748.       _TCHAR* pc = data;
  749.       while (*(pc-1) == ' ')
  750.         pc--;
  751.       *pc = 0;
  752.       while (*(++data) == ' ')
  753.         ;
  754.     }
  755.     _TCHAR* valName = _tcschr(entry, '|');
  756.     if (valName)
  757.       *valName = '\\';  // Replace value name separator with \ for query
  758.  
  759.     // Now lookup keys-value part to get its data and see if it matches the
  760.     // data value from the instream
  761.     //
  762.     _TCHAR buf[300];
  763.     uint32 bufSize = sizeof buf;
  764.     if (baseKey.QueryDefValue(entry, buf, &bufSize) != S_OK
  765.         || (data && _tcscmp(data, buf) != 0))
  766.       diffCount++;
  767.   }
  768.   return diffCount;
  769. }
  770.  
  771. //
  772. // Unregisters entries given a reglist, an optional overrides regItem.
  773. // Return the # of errors deleting keys
  774. //
  775. int
  776. TRegistry::Unregister(TRegList& regInfo, TUnregParams* params, TRegItem* overrides)
  777. {
  778.   int  errorCount = 0;
  779.  
  780.   // Loop thru unregister params to nuke each root level key, thus cleaning
  781.   // up all nested keys too
  782.   //
  783.   for (int i = 0; params[i].Name && params[i].BaseKey; i++) {
  784.     const _TCHAR* regKey = regInfo[params[i].Name];
  785.  
  786.     // If the param not found & it matches the overrides item, then use that
  787.     // value
  788.     //
  789.     if (!regKey && overrides && _tcscmp(overrides->Key, params[i].Name) == 0)
  790.       regKey = overrides->Value;
  791.  
  792.     // If key-value was found, unregister it
  793.     //
  794.     if (regKey) {
  795.       _TCHAR buff[16];
  796.       if (params[i].Prepend) { // Special case prepending char to key
  797.         buff[0] = '.';
  798.         _tcscpy(buff+1, regKey);
  799.         regKey = buff;
  800.       }
  801.  
  802.       // Nuke the key, using the basekey as a reference point
  803.       //
  804.       if (params[i].BaseKey->NukeKey(regKey))
  805.         errorCount++;         // Should throw exception if certain errors?
  806.     }
  807.   }
  808.   return errorCount;
  809. }
  810.  
  811.